package io.lkt.task.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

@Slf4j
public class ToolUtil {

    /**
     * MD5方法
     * @param text 明文
     * @return 密文
     * @throws Exception
     */
    public static String md5Encode(String text) throws Exception {
        //加密后的字符串
        String encodeStr= DigestUtils.md5Hex(text + SysConstant.MD5_KEY);
        log.info("[encodeStr] = " + encodeStr);
        return encodeStr;
    }

    /**
     * MD5验证方法
     * @param text 明文
     * @param md5 密文
     * @return true/false
     * @throws Exception
     */
    public static boolean verify(String text, String md5) throws Exception {
        //根据传入的密钥进行验证
        String md5Text = md5Encode(text);
        if(md5Text.equalsIgnoreCase(md5))
        {
            log.info("verify succ");
            return true;
        }

        return false;
    }

    /**
     * 生成md5
     *
     * @param message
     * @return
     */
    public static String getMD5(String message) {
        String md5str = "";
        try {
            // 1 创建一个提供信息摘要算法的对象，初始化为md5算法对象
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 2 将消息变成byte数组
            byte[] input = message.getBytes();

            // 3 计算后获得字节数组,这就是那128位了
            byte[] buff = md.digest(input);

            // 4 把数组每一字节（一个字节占八位）换成16进制连成md5字符串
            md5str = bytesToHex(buff);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5str.toLowerCase();
    }

    /**
     * 二进制转十六进制
     *
     * @param bytes
     * @return
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuffer md5str = new StringBuffer();
        // 把数组每一字节换成16进制连成md5字符串
        int digital;
        for (int i = 0; i < bytes.length; i++) {
            digital = bytes[i];

            if (digital < 0) {
                digital += 256;
            }
            if (digital < 16) {
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString().toUpperCase();
    }

    /**
     * 随机指定范围内N个不重复的数
     * 在初始化的无重复待选数组中随机产生一个数放入结果中，
     * 将待选数组被随机到的数，用待选数组(len-1)下标对应的数替换
     * 然后从len-2里随机产生下一个随机数，如此类推
     * @param max  指定范围最大值
     * @param min  指定范围最小值
     * @param n  随机数个数
     * @return int[] 随机数结果集
     */
    public static int[] randomArray(int min,int max,int n){
        int len = max-min+1;

        if(max < min || n > len){
            return null;
        }

        //初始化给定范围的待选数组
        int[] source = new int[len];
        for (int i = min; i < min+len; i++){
            source[i-min] = i;
        }

        int[] result = new int[n];
        Random rd = new Random();
        int index = 0;
        for (int i = 0; i < result.length; i++) {
            //待选数组0到(len-2)随机一个下标
            index = Math.abs(rd.nextInt() % len--);
            //将随机到的数放入结果集
            result[i] = source[index];
            //将待选数组中被随机到的数，用待选数组(len-1)下标对应的数替换
            source[index] = source[len];
        }
        return result;
    }

    /**
     * 随机指定范围内的不重复的数
     * 在初始化的无重复待选数组中随机产生一个数放入结果中，
     * 将待选数组被随机到的数，用待选数组(len-1)下标对应的数替换
     * 然后从len-2里随机产生下一个随机数，如此类推
     * @param max  指定范围最大值
     * @param min  指定范围最小值
     */
    public static int randomNum(int min,int max) {

        Random random = new Random();

        int s = random.nextInt(max)%(max-min+1) + min;

        return s;
    }

    /**
     * 获取字符串化浏览次数
     * @param browseCount
     * @return
     */
    public static String getMicroVideoBrowseCount(int browseCount) {

        if (browseCount < 0) {

            return String.format("%d", 0);

        } else if (browseCount < 10000) {

            return String.format("%d", browseCount);

        } else {

            return String.format("%.1fw", browseCount / 10000.0f);

        }

    }

    /**
     * 计算给定时间与当前的时间差 单位：秒
     * @param date
     * @return
     */
    public static long secondDiff(Date date) {
        Instant specialDateInstant = date.toInstant();

        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime specialDateTime = LocalDateTime.ofInstant(specialDateInstant, zone);
        System.out.println(specialDateTime);
        LocalDateTime now = LocalDateTime.now();

        return ChronoUnit.SECONDS.between(specialDateTime, now);

    }

    /**
     * 通过身份证号码获取出生日期、性别、年龄
     * @param certificateNo
     * @return 返回的出生日期格式：1990-01-01   性别格式：F-女，M-男
     */
    public static Map<String, String> getBirAgeSex(String certificateNo) {
        String birthday = "";
        String age = "";
        String sexCode = "";

        int year = Calendar.getInstance().get(Calendar.YEAR);
        char[] number = certificateNo.toCharArray();
        boolean flag = true;
        if (number.length == 15) {
            for (int x = 0; x < number.length; x++) {
                if (!flag) return new HashMap<String, String>();
                flag = Character.isDigit(number[x]);
            }
        } else if (number.length == 18) {
            for (int x = 0; x < number.length - 1; x++) {
                if (!flag) return new HashMap<String, String>();
                flag = Character.isDigit(number[x]);
            }
        }
        if (flag && certificateNo.length() == 15) {
            birthday = "19" + certificateNo.substring(6, 8) + "-"
                    + certificateNo.substring(8, 10) + "-"
                    + certificateNo.substring(10, 12);
            sexCode = Integer.parseInt(certificateNo.substring(certificateNo.length() - 3, certificateNo.length())) % 2 == 0 ? "F" : "M";
            age = (year - Integer.parseInt("19" + certificateNo.substring(6, 8))) + "";
        } else if (flag && certificateNo.length() == 18) {
            birthday = certificateNo.substring(6, 10) + "-"
                    + certificateNo.substring(10, 12) + "-"
                    + certificateNo.substring(12, 14);
            sexCode = Integer.parseInt(certificateNo.substring(certificateNo.length() - 4, certificateNo.length() - 1)) % 2 == 0 ? "F" : "M";
            age = (year - Integer.parseInt(certificateNo.substring(6, 10))) + "";
        }
        Map<String, String> map = new HashMap<String, String>();
        map.put("birthday", birthday);
        map.put("age", age);
        map.put("sexCode", sexCode);
        return map;
    }

    /**
     * 通过身份证号码获取出生日期
     * @param certificateNo
     * @return 返回的出生日期格式：1990-01-01
     */
    public static String getBirthdayByIdCard(String certificateNo) {
        String birthday = "";

        char[] number = certificateNo.toCharArray();
        boolean flag = true;
        if (number.length == 15) {
            for (int x = 0; x < number.length; x++) {
                if (!flag) {
                    return "";
                }
                flag = Character.isDigit(number[x]);
            }
        } else if (number.length == 18) {
            for (int x = 0; x < number.length - 1; x++) {
                if (!flag) {
                    return "";
                }
                flag = Character.isDigit(number[x]);
            }
        }
        if (flag && certificateNo.length() == 15) {
            birthday = "19" + certificateNo.substring(6, 8) + "-"
                    + certificateNo.substring(8, 10) + "-"
                    + certificateNo.substring(10, 12);
        } else if (flag && certificateNo.length() == 18) {
            birthday = certificateNo.substring(6, 10) + "-"
                    + certificateNo.substring(10, 12) + "-"
                    + certificateNo.substring(12, 14);
        }

        return birthday;
    }

    /**
     * 根据用户生日计算年龄
     */
    public static int getAgeByBirthday(String bir) {

        if(org.apache.commons.lang3.StringUtils.isBlank(bir)){
            return 0;
        }

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate birthDate = LocalDate.parse(bir, formatter);

        LocalDate nowDate = LocalDate.now();
        Period period = Period.between(birthDate, nowDate);

        return period.getYears();
    }

    /**
     * 根据身份证号码计算年龄
     */
    public static int getAgeByIdCard(String certificateNo) {

        String bir = getBirthdayByIdCard(certificateNo);

        if(org.apache.commons.lang3.StringUtils.isBlank(bir)){
            return 0;
        }

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate birthDate = LocalDate.parse(bir, formatter);

        LocalDate nowDate = LocalDate.now();
        Period period = Period.between(birthDate, nowDate);

        return period.getYears();
    }

    /**
     * 获取客户端IP地址
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) {

        String ipAddress = request.getHeader("x-forwarded-for");

        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknow".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();

            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡获取本机配置的IP地址
                InetAddress inetAddress = null;
                try {
                    inetAddress = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress = inetAddress.getHostAddress();
            }
        }

        //对于通过多个代理的情况，第一个IP为客户端真实的IP地址，多个IP按照','分割
        if(null != ipAddress && ipAddress.length() > 15){
            //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",") > 0){
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }

        return ipAddress;
    }

    /**
     * 视频内容检查生效状态
     * @return
     */
    public static boolean getVideoContentCheckEffectStatus(){

        LocalDateTime localDateTime = LocalDateTime.now();

        int hour = localDateTime.getHour();

        if (hour >= 19 && hour <=22) {
            return true;
        }

        return false;
    }

    /**
     * 产生用户唯一标识
     * @return
     */
    public static String generateUserUniqueId() {

        long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));

        String secondStr = String.valueOf(second);

        int randonNum = randomNum(10000000, 99999999);

        String tempSecondStr = secondStr.substring(1);

        long finalUniqueId = Long.parseLong(tempSecondStr) + randonNum;

        return String.valueOf(finalUniqueId);
    }

    /**
     * 产生订单ID
     * @return
     */
    public static String generateOrderId() {

        String dateString = DateUtil.getFormatDate("yyyyMMddHHmmssSSS", DateTime.now());

        int randonNum = randomNum(1000000, 9999999);

        return dateString + randonNum;

    }

    /**
     * 安卓微信支付APPID时间切换状态
     * @return
     */
    public static boolean getAndroidWxPayAppIdChangeStatus(){

        LocalDateTime localDateTime = LocalDateTime.now();

        int hour = localDateTime.getHour();

        if (hour >= 7 && hour <= 22) {
            return true;
        }

        return false;
    }

    /**
     * 获取是否是上午状态 true-是上午时段 false-下午时段
     * @return
     */
    public static boolean getAmPmTimePeriodStatus(){

        LocalDateTime localDateTime = LocalDateTime.now();

        int hour = localDateTime.getHour();

        if (hour >= 0 && hour <= 12) {
            return true;
        }

        return false;
    }

    public static void main(String[] args) throws Exception {
        //System.out.println(randomNum(80, 90));
        //System.out.println(getMicroVideoBrowseCount(556686));

        //System.out.println(idCardVerify("410725198809062838", "别赛男"));

        //Date date = new Date(2018, 3, 10, 16, 10, 10);
        //System.out.println(date);

        //System.out.println(secondDiff(date));
//        System.out.println(getBirAgeSex("410725198909062838"));
//        System.out.println(getAgeByBirthday("2000-04-21"));
//        System.out.println(getBirthdayByIdCard("41072519890906283x"));
//        System.out.println(getAgeByIdCard("41072520000421283x"));

//        System.out.println(LocalDateTime.now());
//        //System.out.println(LocalDateTime.now() + " " + checkIpAddrCnSource("195.16.187.50"));
//        System.out.println(LocalDateTime.now());
//
//        System.out.println(randomNum(100000000, 999999999));
//        System.out.println(generateUserUniqueId());
//
//        System.out.println(generateOrderId());

        //System.out.println(md5Encode(1000005 + "oQdug0Sbss2o6K9Ckfgl7Vki1oF8"));

        //System.out.println(md5Encode("1000005oQdug0Sbss2o6K9Ckfgl7Vki1oF8"));

        //downloadAvatarPic("http://thirdwx.qlogo.cn/mmopen/fFgUJknhibCwWFr6ibmJR4ibo1vMS1V7QyZRBy3nug8lib5bV1C5WhvWPhDJojn3R6KLdNWW0eq0wkOeTkAZZVC9tA/132", "1000006_avatar.png");

    }

}
